/*
 * Copyright (C) 2013 The original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.zapta.apps.maniana.persistence;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.zapta.apps.maniana.annotations.ApplicationScope;
import com.zapta.apps.maniana.model.AppModel;
import com.zapta.apps.maniana.model.ItemColor;
import com.zapta.apps.maniana.model.ItemModelReadOnly;
import com.zapta.apps.maniana.model.ItemRepeatReadOnly;
import com.zapta.apps.maniana.model.PageKind;
import com.zapta.apps.maniana.persistence.StoreIF;

/**
 * Serializes a model to a JSON doc.
 *
 * @author Tal Dayan
 * @author Elliott Mitchell
 */
@ApplicationScope
public class ModelSerialization implements FieldNames {

    // Format Step:
    // 1: initial. Model fields at top level, with format.
    // 2: added top level "metadata". Move model fields to "model". Format field stays at
    // top level.
    // 3: added due date, early/late colors, and model show early fields

    public static final String serializeModel(AppModel model, PersistenceMetadata metadata) {
        try {
            final JSONObject root = new JSONObject();
            root.put(FIELD_FORMAT, FORMAT_STEP);
            root.put(FIELD_METADATA, metadata.toJson());
            root.put(FIELD_MODEL, modelToJson(model));

            // NOTE: using indent of only 1 to reduce file size.
            return root.toString(1);
        } catch (JSONException e) {
            throw new RuntimeException("JSON serialization error", e);
        }
    }

    /** Serialize a model to a JSON object. */
    private static final JSONObject modelToJson(AppModel model) throws JSONException {
        final JSONObject root = new JSONObject();
        root.put(FIELD_LAST_PUSH_DATE, model.getLastPushDateStamp());
        root.put(FIELD_ITEMS, pageItemsToJson(model));
        return root;
    }

    /** Serialize one page */
    private static final JSONArray pageItemsToJson(AppModel appModel)
            throws JSONException {

        final JSONArray result = new JSONArray();
        int n = appModel.getPageItemCount(PageKind.TODAY);
        for (int i = 0; i < n; ++i) {
            result.put(itemToJson(appModel.getItemReadOnly(PageKind.TODAY, i)));
        }
        n = appModel.getPageItemCount(PageKind.TOMORROW);
        for (int i = 0; i < n; ++i) {
            result.put(itemToJson(appModel.getItemReadOnly(PageKind.TOMORROW, i)));
        }
        return result;
    }

    /** Serialzie one item */
    private static final JSONObject itemToJson(ItemModelReadOnly itemModel) throws JSONException {
        final JSONObject result = new JSONObject();
        result.put(FIELD_UPDATE_TIME, itemModel.getUpdateTime());
        result.put(FIELD_ID, itemModel.getId());
        result.put(FIELD_TEXT, itemModel.getText());
        final String textExt=itemModel.getTextExt();
        if(textExt!=null&&textExt.length()!=0) result.put(FIELD_TEXT_EXT, textExt);
        if (itemModel.isCompleted()) {
            result.put(FIELD_DONE, itemModel.getCompletionDate());
        }
        if (itemModel.getDueDate() > 0) {
            result.put(FIELD_DUE_DATE, itemModel.getDueDate());
            if(itemModel.getShowEarly() != 0) result.put(FIELD_SHOW_EARLY,
itemModel.getShowEarly());
            if (itemModel.getColorEarly() != itemModel.getColorDue())
result.put(FIELD_COLOR_EARLY, itemModel.getColorEarly().getKey());
            if (itemModel.getColorLate() != itemModel.getColorDue())
result.put(FIELD_COLOR_LATE, itemModel.getColorLate().getKey());

            ItemRepeatReadOnly repeat = itemModel.getRepeatRO();
            if(repeat != null ) {
                final StoreIF store = new StoreIF(result);
                repeat.toStore(store);
            }
        } else if (itemModel.getDueDate() != 0) {
            result.put(FIELD_DUE_DATE, itemModel.getDueDate());
        }
        if (itemModel.getColorDue() != ItemColor.NONE) {
            result.put(FIELD_COLOR, itemModel.getColorDue().getKey());
        }
        return result;
    }

}
